# -*- coding:utf-8 -*-
# @Author: komeiji satori

from sanic import Sanic, request, response

app = Sanic("sanic_service")


@app.get("/text")
async def text(request: request.Request):
    # 里面传入一个字符串即可, 至于状态码、响应头可以根据自身需求决定是否设置
    return response.text("text")


@app.get("/json")
async def json(request: request.Request):
    # 第一个参数传入一个字典即可
    return response.json({"name": "古明地觉", "age": 16}, ensure_ascii=False)


@app.get("/html")
async def html(request: request.Request):
    # 里面也接收一个字符串, 如果是文件的话, 可以先读取出来
    # 当然还可以使用 jinja2 进行渲染
    return response.html("<h3>古明地觉</h3>")


@app.get("/file")
async def file(request: request.Request):
    # 由于调用 response.file 会得到一个协程, 因此我们需要使用 await
    # 接收如下参数:
    """
    location: 要返回的文件的路径, 必传参数
    status: 成功响应时的 http 状态码 200, 正常返回的话无需修改
    mime_type: 如果为空, 内部会通过 mimetypes 模块的 guess_type 函数进行推断
    headers: 自定义 http 响应头
    filename: 文件名, 如果传递了会写入到响应头 headers 的 Content-Disposition 中
    """
    return await response.file("1.txt")


@app.get("/raw")
async def raw(request: request.Request):
    # 和 text 非常类似, 但是它第一个参数接收的不是字符串、而是字节串
    return response.raw(b"komeiji satori")


@app.get("/stream")
async def stream(request: request.Request):
    # Sanic 返回流数据给浏览器, 不是一次性把所有数据返回, 而是一部分一部分地返回
    # 参数如下:
    """
    streaming_fn: 用于写流响应数据的协程函数
    status: 状态码, 默认 200
    headers: 自定义的 http 响应头
    content_type: 默认是纯文本的 content_type, 可以根据实际情况进行修改
    """

    # 定义协程函数
    async def streaming_fn(res):
        await res.write("你好呀\n")
        import asyncio

        await asyncio.sleep(3)
        await res.write("古明地觉")

    # 但是浏览器访问的时候, 并不是先看到 "你好呀\n", 然后 3s 后看到 "古明地觉"
    # 而是 3s 之后一起显示, 因为浏览器上面一旦显示内容, 就代表这一次请求已经结束了
    # 所以是整体一起显示的
    return response.stream(streaming_fn)


@app.get("/file_stream")
async def file_stream(request: request.Request):
    # 从名字上看, 这是 file 和 stream 的结合
    # file_stream 也是返回文件, 但它是一边读一边返回, 每次返回一定大小的数据
    # 而 file 则是一次性返回所有数据, 很明显当文件过大时, file_stream 可以大大节省内存
    """
    参数相比 response.file 会多一个 chunk_size, 表示每次读取的文件数据大小, 默认 4096
    如果是 file_stream, 你会发现响应头中少了 Content-Length, 因为流的形式每次只是返回一个 chunk, 无法得知整个文件的大小
    但是多了一个 Transfer-Encoding
    """
    return await response.file_stream("1.txt")


@app.get("/redirect")
async def redirect(request: request.Request):
    # 会跳转到路由 /text
    return response.redirect("/text")


if __name__ == "__main__":
    app.run(host="127.0.0.1", port=8888)
